/**
 * @file literal-buffer.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-04-01
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef JSASM_LITERAL_BUFFER_H_
#define JSASM_LITERAL_BUFFER_H_

#include "src/base/strings.h"
#include "src/base/vector.h"
#include "src/common/globals.h"

class LiteralBuffer final {
    public:
        LiteralBuffer() : backing_store_(), position_(0), is_one_byte_(true) {}

        ~LiteralBuffer() { backing_store_.Dispose(); }

        LiteralBuffer(const LiteralBuffer&) = delete;

        LiteralBuffer& operator=(const LiteralBuffer&) = delete;

        JSASM_INLINE void AddChar(char code_unit) {
            AddOneByteChar(static_cast<byte>(code_unit));
        }

        JSASM_INLINE void AddChar(base::uc32 code_unit) {
            if (is_one_byte()) {
                if (code_unit <= static_cast<base::uc32>(unibrow::Latin1::kMaxChar)) {
                    AddOneByteChar(static_cast<byte>(code_unit));
                    return;
                }
                ConvertToTwoByte();
            }
            AddTwoByteChar(code_unit);
        }

        bool is_one_byte() const { return is_one_byte_; }

        bool Equals(base::Vector<const char> keyword) const {
            return is_one_byte() && keyword.length() == position_ &&
                (memcmp(keyword.begin(), backing_store_.begin(), position_) == 0);
        }

        template <typename Char>
        base::Vector<const Char> literal() const {
            return base::Vector<const Char>(
                reinterpret_cast<const Char*>(backing_store_.begin()),
                position_ >> (sizeof(Char) - 1)
            );
        }

        int length() const { return is_one_byte() ? position_ : (position_ >> 1); }

        void Start() {
            position_ = 0;
            is_one_byte_ = true;
        }

    private:
        static const int kInitialCapacity = 16;
        static const int kGrowthFactor = 4;
        static const int kMaxGrowth = 1 * MB;

        JSASM_INLINE bool IsValidAscii(char code_unit) {
            return iscntrl(code_unit) || isprint(code_unit);
        }

        JSASM_INLINE void AddOneByteChar(byte one_byte_char) {
            if (position_ >= backing_store_.length()) ExpandBuffer();
            backing_store_[position_] = one_byte_char;
            position_ += kOneByteSize; 
        }

        void AddTwoByteChar(base::uc32 code_unit);

        int NewCapacity(int min_capacity);

        void ExpandBuffer() {};

        void ConvertToTwoByte();

        base::Vector<byte> backing_store_;

        int position_;

        bool is_one_byte_;
};

#endif // JSASM_LITERAL_BUFFER_H_